﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using WebApplication.BaseClass;

namespace WebApplication.MessageContent
{
    public class WeiXinContextGlobal
    {
        public static object Lock = new object();

        public static bool UserWeixinContext = true;
    }


    public class WeixinContextRemovedEventArgs : EventArgs
    {

        public IMessageContext MessageContext { get; set; }

        public string OpenId
        {
            get
            {
                return MessageContext.UserName;
            }
        }

        public DateTime LastActiveTime
        {
            get
            {
                return MessageContext.LastActiveTime;
            }
        }

        public WeixinContextRemovedEventArgs(IMessageContext messageContext)
        {
            MessageContext = messageContext;
        }
    }


    public class WeixinContext<TM> where TM : class, IMessageContext, new()
    {
        private const int DEFAULTEXPIREMINUTES = 90;

        protected Dictionary<string, TM> MessageCollection { get; set; }

        protected List<TM> MessageQueue { get; set; }

        public double ExpireMinutes { get; set; }

        public int MaxReocrdCount { get; set; }

        public WeixinContext()
        {
            Restore();
        }

        public void Restore()
        {
            MessageCollection = new Dictionary<string, TM>(StringComparer.OrdinalIgnoreCase);
            MessageQueue = new List<TM>();
            ExpireMinutes = DEFAULTEXPIREMINUTES;
        }

        private TM GetMessageContext(string userName)
        {
            while (MessageQueue.Count > 0)
            {
                var firstMessageContext = MessageQueue[0];
                var timeSpan = DateTime.Now - firstMessageContext.LastActiveTime;
                if (timeSpan.Minutes >= ExpireMinutes)
                {
                    MessageQueue.RemoveAt(0);
                    MessageCollection.Remove(firstMessageContext.UserName);

                    firstMessageContext.OnRemoved();
                }
                else
                {
                    break;
                }
            }
            if (!MessageCollection.ContainsKey(userName))
            {
                return null;
            }

            return MessageCollection[userName];
        }

        private TM GetMessageContext(string userName, bool createIfNotExists)
        {
            var messageContext = GetMessageContext(userName);

            if (messageContext == null)
            {
                if (createIfNotExists)
                {
                    MessageCollection[userName] = new TM()
                    {
                        UserName = userName,
                        MaxRecordCount = MaxReocrdCount
                    };
                    messageContext = GetMessageContext(userName);

                    MessageQueue.Add(messageContext);
                }
                else
                {
                    return null;
                }
            }
            return messageContext;
        }

        public TM GetMessageContext(IRequestMessageBase requestMessage)
        {
            lock (WeiXinContextGlobal.Lock)
            {
                return GetMessageContext(requestMessage.FromUserName, true);
            }
        }

        public TM GetMessageContext(IResponseMessageBase responseMessage)
        {
            lock(WeiXinContextGlobal.Lock)
            {
                return GetMessageContext(responseMessage.ToUserName, true);
            }
        }

        public void InsertMessage(IRequestMessageBase requestMessage)
        {
            lock (WeiXinContextGlobal.Lock)
            {
                var userName = requestMessage.FromUserName;
                var messageContext = GetMessageContext(userName, true);
                if (messageContext.RequestMessage.Count > 0)
                {
                    var messageContextInQueue = MessageQueue.FindIndex(z => z.UserName == userName);
                    if (messageContextInQueue >= 0)
                    {
                        MessageQueue.RemoveAt(messageContextInQueue);
                        MessageQueue.Add(messageContext);
                    }
                }
                messageContext.LastActiveTime = DateTime.Now;
                messageContext.RequestMessage.Add(requestMessage);
            }
        }

        public void InsertMessage(IResponseMessageBase responseMessage)
        {
            lock(WeiXinContextGlobal.Lock)
            {
                var messageContext = GetMessageContext(responseMessage.ToUserName, true);

                messageContext.ResponseMessage.Add(responseMessage);
            }
        }


        public IRequestMessageBase GetLastRequestMessage(string userName)
        {
            lock(WeiXinContextGlobal.Lock)
            {
                var messageContext = GetMessageContext(userName, true);
                return messageContext.RequestMessage.LastOrDefault();
            }
        }

        public IResponseMessageBase GetLastResponseMessage(string userName)
        {
            lock(WeiXinContextGlobal.Lock)
            {
                var messageContext = GetMessageContext(userName, true);
                return messageContext.ResponseMessage.LastOrDefault();
            }
        }
    }
}